This section is solely of interest to those who want to implement a NAND Flash Chip device driver. Application programs will use only the public ANC API.
The chip device driver consists of two parts, common code and chip-specific code.
The common code performs:
ONFI operations like interrogation and bad-block management;
conventional chip interrogation; many of the chips on the market follow a
common device identifier coding, and many of them mark bad blocks by
setting the first byte of the spare area of the first page to zero; chips
whose device identifier is listed in the table of known chip types
cyg_nand_chip_id[]
in
packages/io/flash_nand/current/src/io_nand_chip.c,
and that adhere to the factory-bad marking convention will be called
'regular' below;
BBT (Bad Block Table) management, in a manner compatible with Linux MTD and u-boot.
The chip-specific component must provide the following code:
in case of an ONFI chip: nothing, apart from allocating a device driver
struct with the type set to ONFI
;
in case of a regular non-ONFI chip: nothing, apart from allocating a device
driver struct with the type set to REGULAR
;
otherwise: code to correctly interpret the Read ID
command and to query/set factory-defined bad-block markers.
The NAND Flash Chip API is specified in cyg/io/flash_nand_chip.h.
If a chip is ONFI-conformant or regular, then the generic code in the common NAND Flash chip module can be used; in this case, there is no need for chip-specific code in the chip device driver.
The information on a chip that is used by the NAND Flash controller is
recorded in the chip device's info structure (which reflects ONFI's
Read Parameter
response):
typedef enum CYG_NAND_FEATURES_FLAGS { CYGNUM_NAND_FEATURES_FLAGS_x16 = (0x1 << 0), ... } cyg_nand_flags_features_t; typedef enum CYG_NAND_OPTIONAL_FLAGS { CYGNUM_NAND_OPTIONAL_FLAGS_PROGRAM_CACHE = (0x1 << 0), CYGNUM_NAND_OPTIONAL_FLAGS_READ_CACHE = (0x1 << 1), ... CYGNUM_NAND_OPTIONAL_FLAGS_COPYBACK = (0x1 << 4), ... } cyg_nand_flags_optional_t; typedef struct CYG_NAND_CHIP_INFO { cyg_nand_flags_features_t flags_features; cyg_nand_flags_optional_t flags_optional; cyg_uint8 manufacturer[12]; /**< filled with ' ' */ cyg_uint8 model[20]; /**< filled with ' ' */ ... cyg_uint32 data_bytes_per_page; cyg_uint16 spare_bytes_per_page; cyg_uint32 pages_per_block; cyg_uint32 blocks_per_lun; cyg_uint8 luns; ... cyg_uint8 t_write_enable_pulse; /**< in ns */ cyg_uint8 t_read_enable_pulse; /**< in ns */ ... } cyg_nand_chip_info_t; |
flags_features
has the bit
CYGNUM_NAND_FEATURES_FLAGS_x16
set if
the device has x16 organisation; else, it has x8 organisation.
flags_optional
describes various optional capabilities
of the chip. A lun
(Logical UNit) may be a plane
etc within the chip. As far as ONFI is concerned, a "chip" is something
that has its own nCE (Chip Enable) line. If a physical chip has multiple
NAND arrays that can separately be enabled by their own nCE line, the
NAND arrays must be considered as separate chips, and each must have a
separate NAND Flash Chip device driver. The controller's dispatch function
chip_select()
must be used for selection of the correct
NAND array.
Because ONFI is recent, many large-page chips support most of the ONFI command
set (e.g. page program command = 0x80), but they are often not *completely*
compliant. Usually, the interrogation command is custom, as is the format
for bad block marks. For interrogation, non-ONFI chips support a
Read ID
command, which returns 2 to 5 bytes of
information. The first byte is always the manufacturer code, the second
byte is always the chip model code. The meaning of bytes 3..5 (insofar
as they are present) is usually standardized: byte 3 encodes the number
of chips within the package, and indicates whether interleaved or cached
access is supported; byte 4 encodes page data and spare size, block size,
x8/x16 organisation, and minimum timing information; and byte 5 encodes the
number of planes/LUNs, and data size per LUN.
The common part of the NAND Flash Chip library has an implementation for ONFI chips and an implementation for regular non-ONFI chips. A custom device driver is only necessary for non-regular, non-ONFI chips.
ONFI-compliant and regular chips have no need for device-specific code. Non-regular, non-ONFI chips must create a function dispatch table for their device driver.
/** * Function dispatch table that must be used for non-ONFI, non-regular * chips. */ typedef struct CYG_NAND_CHIP_FUNS { int (*chip_init)(cyg_nand_ctl_t *ctl, cyg_nand_chip_t *chip); /** parse the 'Read ID' block info. */ int (*chip_parse_info)(cyg_nand_ctl_t *ctl, cyg_nand_chip_t *chip, const cyg_uint8 *block); /** * Check for factory-marked bad blocks * @param row: row address, includes (ignored) page * @return 0 -> good; 1 -> bad; -errno : error */ int (*chip_block_is_bad)(const cyg_nand_chip_t *chip, size_t row); } cyg_nand_chip_funs_t; |
chip_init()
performs any pre-interrogation
initialization. Typically, the slowest communication mode is
chosen. The controller then performs interrogation, and afterwards invokes
chip_parse_info()
. Any information that cannot be derived
from interrogation must be filled in in chip_parse_info()
,
based on the datasheet. chip_block_is_bad()
performs factory-bad-block query in the manner prescribed in the datasheet.
/** * Type of chip */ typedef enum CYG_NAND_CHIP_TYPE { CYG_NAND_CHIP_TYPE_ONFI, CYG_NAND_CHIP_TYPE_REGULAR, CYG_NAND_CHIP_TYPE_CUSTOM, } cyg_nand_chip_type_t; /** * Boolean capabilities of the NAND Flash chip */ typedef enum CYG_NAND_CHIP_FLAGS { CYG_NAND_CHIP_FLAGS_CMD_IS_SMALLPAGE = (0x1 << 1), CYG_NAND_CHIP_FLAGS_DATA_x16 = (0x1 << 2), CYG_NAND_CHIP_FLAGS_NO_BBT = (0x1 << 3), } cyg_nand_chip_flags_t; /** * NAND Flash Chip device driver structure */ struct CYG_NAND_CHIP { const cyg_nand_chip_funs_t *funs; /**< Non-ONFI dispatch table */ cyg_uint32 devno; /**< My devno */ cyg_uint32 anc_devno; /**< Owning ANC devno */ cyg_uint32 ctl_devno; /**< Owning controller devno */ /** If not ONFI, set a bit in the mask for each meaningful * byte in the 'Read ID' response. */ cyg_uint32 bytes_mask; cyg_nand_chip_flags_t flags; int initialized; cyg_nand_chip_info_t info; cyg_nand_ctl_t *ctl; /**< My controller */ cyg_nand_bbt_t bbt; /**< Bad Block Table */ cyg_uint8 spare_buffer[CYGNUM_NAND_SPARE_MAX]; }; |
If a chip is initialised with the bit
CYG_NAND_CHIP_FLAGS_NO_BBT
cleared in its
cyg_nand_chip->flags
field, the initialization routine
looks for blocks that contain a previously created BBT (Bad Block
Table) in some regions of the chip. If no BBT is found, the whole chip is
scanned for factory-bad blocks using
chip->chip_block_is_bad()
, and the BBT is recorded on
the chip. If bit CYG_NAND_CHIP_FLAGS_NO_BBT
is
set, the only bad-block management that is possible is by inspecting
factory-bad blocks. This is not recommended policy.
#define CYG_NAND_DRIVER_CHIP(name, i_funs, i_devno, i_anc, i_ctl, i_type, i_flags, i_bytes_mask) \ cyg_nand_chip_t name CYG_HAL_TABLE_ENTRY(cyg_nand_dev_chip) = { \ .funs = i_funs, \ .devno = i_devno, \ .anc_devno = i_anc, \ .ctl_devno = i_ctl, \ .type = i_type, \ .flags = i_flags, \ .bytes_mask = i_bytes_mask, \ } |
A NAND Flash chip device structure is instantiated with macro
CYG_NAND_DRIVER_CHIP()
. The values for
devno
, anc_devno
,
ctl_devno
, type
, and
flags
are usually specified in the target
CDL. ONFI chips must set the type
field to
CYG_NAND_CHIP_TYPE_ONFI
, and funs
can be NULL
. Regular chips must set the
type
to
CYG_NAND_CHIP_TYPE_REGULAR
, and
funs
can be NULL
. Otherwise,
funs
must point to a struct that contains the
dispatch table for this type of chip, and bytes_mask
describes how much Read ID
information is present:
it must have set (0x1 << bytenum)
for each meaningful
byte bytenum
.